﻿using SuperX.Common;
using SuperX.Common.BasicService;
using SuperX.Common.Helper;
using SuperX.Common.Log;
using SuperX.Common.Object;
using SuperX.DataService.Abstract;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;

namespace SuperX.MiddlewareBase
{
    public abstract class ChannelBase : BasicObject
    {
        /// <summary>
        /// 标签对象
        /// </summary>
        public IIOTag Tag { get; set; }

        /// <summary>
        /// 角色
        /// </summary>
        public Roles Roles { get; set; }

        /// <summary>
        /// Tag名称
        /// </summary>
        [Helper.Validation.Empty]
        public string TagName { get; set; }

        /// <summary>
        /// 自定义主题
        /// </summary>
        public object CustomThemes { get; set; }

        /// <summary>
        /// 队列锁
        /// </summary>
        public object QueueLock = new object();

        public ManagerBase Manager { get => Parent?.Parent as ManagerBase; }

        public ServerBase Host { get => Parent as ServerBase; }

        /// <summary>
        /// 通道状态
        /// </summary>
        public bool ChannelState { get; set; } = false;

        public string GroupKey { get; set; }

        public string AssetCode { get; set; }

        public override string FullName
        {
            get
            {
                if (Parent != null && Parent.FullName != null && !string.IsNullOrEmpty(GroupKey))
                {
                    return $"{Parent.FullName}.{GroupKey}.{Name}";
                }
                return base.FullName;
            }
        }

        public virtual void Init()
        {
            try
            {
                Connect();
                switch (Roles)
                {
                    case Roles.Producer:
                        BindTag();
                        Manager.ProcessingTagValue += ProcessingTagValue;
                        break;

                    case Roles.Consumers:
                        InitSubscribe();
                        break;

                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                Logger.ErrorException(ex);
            }
        }

        public abstract bool GetSendState();

        public virtual void Connect()
        { }

        public abstract void Publish(string data);

        public virtual void InitSubscribe()
        {
        }

        public virtual void Stop()
        {
            if (Tag != null) Tag.ValueChanged -= OnValueChanged;
            if (Manager?.ProcessingTagValue != null) Manager.ProcessingTagValue -= ProcessingTagValue;
        }

        public virtual void ProcessingTagValue()
        {
            var QueueCaches = new ConcurrentQueue<DataCache>();
            lock (QueueLock)
            {
                QueueCaches = ChannelQueue;
                ChannelQueue = new ConcurrentQueue<DataCache>();
            }
            if (!GetSendState())
            {
                ChannelState = false;
                AddCache(QueueCaches);
                Connect();//尝试重连接通道
                return;
            }
            if (ChannelState != GetSendState() && GetSendState())
            {
                ChannelState = true;
                if (!SendCacheData())//连接状态改变，查数据库缓存并发送
                {
                    AddCache(QueueCaches);
                    ChannelState = false;
                    return;
                }
            }
            if (QueueCaches.Count > 0) Send(QueueCaches);//发送队列数据
        }

        private void Send(ConcurrentQueue<DataCache> QueueItems)
        {
            bool IsSendNormal = true;
            while (!QueueItems.IsEmpty)
            {
                if (QueueItems.TryDequeue(out DataCache QueueItem))
                {
                    try
                    {
                        var data = JsonHelper.JsonSerialize(QueueItem);
                        Publish(data);
                    }
                    catch (Exception ex)
                    {
                        IsSendNormal = false;
                        Logger.ErrorException(ex);
                        Logger.Warn($"{QueueItem.TagName}发送失败！值：{QueueItem.TagValue}");
                        AddCache(QueueItem);
                    }
                }
                if (!IsSendNormal)//中途出错！后面的数据直接入库
                {
                    AddCache(QueueItems);
                    ChannelState = false;
                    break;
                }
            }
        }

        /// <summary>
        /// 通道队列
        /// </summary>
        public ConcurrentQueue<DataCache> ChannelQueue = new ConcurrentQueue<DataCache>();

        /// <summary>
        /// 绑定Tag
        /// </summary>
        public void BindTag()
        {
            try
            {
                var iOTags = BasicServiceManager.GetProjService().Project.Objects;
                if (iOTags.ContainsKey(TagName))
                {
                    Tag = iOTags[TagName] as IIOTag;
                    TagInitPush(Tag);
                    if (Tag != null) Tag.ValueChanged += OnValueChanged;
                }
            }
            catch (Exception ex)
            {
                Logger.ErrorException(ex);
            }
        }

        private void TagInitPush(IIOTag tag)
        {
            var assetCode = (tag.Parent.Parent as IDriver).DriverNO;
            if (tag.Value == null) return;
            ChannelQueue.Enqueue(new DataCache()
            {
                QueueName = FullName,
                TagName = TagName,
                TagValue = JsonHelper.JsonSerialize(new { Value = tag.Value, tag.Quality }),
                ChangedTime = DateTime.Now,
                AssetCode = assetCode,
            });
        }

        public virtual void OnValueChanged(object sender, TagChangedEventArgs e)
        {
            try
            {
                lock (QueueLock)
                {
                    var tag = sender as IIOTag;
                    var assetCode = (tag.Parent.Parent as IDriver).DriverNO;
                    ChannelQueue.Enqueue(new DataCache()
                    {
                        QueueName = FullName,
                        TagName = TagName,
                        TagValue = JsonHelper.JsonSerialize(new { Value = (sender as IIOTag).Value, (sender as IIOTag).Quality }),
                        ChangedTime = DateTime.Now,
                        AssetCode = assetCode,
                    });
                }
            }
            catch (Exception ex)
            {
                Logger.ErrorException(ex);
            }
        }

        /// <summary>
        /// 将消息添加到待入库集合
        /// </summary>
        /// <param name="QueueMsgCache"></param>
        public void AddCache(DataCache TagItem)
        {
            Manager?.FailMsgList.Add(TagItem);
        }

        /// <summary>
        /// 将消息添加到待入库集合
        /// </summary>
        /// <param name="TagItems"></param>
        public void AddCache(ConcurrentQueue<DataCache> TagItems)
        {
            Manager?.FailMsgList.AddRange(TagItems);
        }

        /// <summary>
        /// 发送数据库缓存
        /// </summary>
        /// <returns></returns>
        private bool SendCacheData()
        {
            try
            {
                var datas = Manager?.GetCacheData(FullName);
                if (datas.Count > 0)
                {
                    var deleteList = new List<DataCache>();
                    foreach (var data in datas)
                    {
                        try
                        {
                            Publish(data.TagValue);
                            deleteList.Add(new DataCache() { Id = data.Id });
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorException(ex);
                            Logger.Warn($"数据库缓存发送出现错误!");
                            return false;
                        }
                    }
                    Manager?.Db.Deleteable(deleteList).ExecuteCommand();//删除这批发送成功的数据
                }
            }
            catch (Exception ex)
            {
                Logger.ErrorException(ex);
                return false;
            }
            return true;
        }
    }

    public enum Roles
    {
        [Description("发布者")]
        Producer,

        [Description("消费者")]
        Consumers,

        //[Description("发布者或者消费者")]
        //ProducerAndConsumers
    }

    public enum SendMethod
    {
        /// <summary>
        /// 值变化
        /// </summary>
        [Description("值变化")]
        ValueChanged,

        /// <summary>
        /// 定时
        /// </summary>
        //[Description("定时")]
        //Timing
    }
}